package com.sir.tao.carhire.shiro;

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import lombok.Data;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;
import org.crazycake.shiro.RedisManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.servlet.Filter;
import java.time.Duration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author dyy
 * @data 2021/12/6 17:11
 * @description:
 */
@Configuration
@Data
public class ShiroUtil {

    private String host = "localhost";
    private int port = 6379;
    private Duration timeout;



    /**
     * Filter工厂，设置对应的过滤条件和跳转条件
     *
     * @return ShiroFilterFactoryBean
     */
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getFilterFactoryBean(DefaultWebSecurityManager manager){
        //1.创建shiro过滤工厂
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //2.设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(manager);
        //3.通用配置,如果没有前后端分离配置这个（配置登录页面，登录成功页面，验证未成功页面）
//      filterFactory.setLoginUrl("/autherror?code=1"); //设置登录页面
//      filterFactory.setUnauthorizedUrl("/autherror?code=2"); //授权失败跳转页面

        //配置url请求过滤条件
        //过滤url请求，使用anon任何人都能访问
        /*
         *   url过滤 条件 简写
         *   anon 匿名  所有用户未登陆时都能访问的窗口
         *   authc 需要登陆认证后才能访问
         *
         *
         * */
//        //5.设置自定义JWT过滤器
        Map<String , Filter> jwt = new HashMap<>();
        jwt.put("jwt",new JwtFilter());
        shiroFilterFactoryBean.setFilters(jwt);

        //6.设置所有请求都经过我们的JWTFilter，自定义url规则

        Map<String,String> stringStringHashMap = new LinkedHashMap<>();
        //所有的请求都经过我们的Filter

        stringStringHashMap.put("/administrators/**","anon");
        stringStringHashMap.put("/business/**","anon");
        stringStringHashMap.put("/userBusiness/**","anon");
        stringStringHashMap.put("/swagger-ui.html","anon");

        stringStringHashMap.put("/swagger-resources/**","anon");
        stringStringHashMap.put("/v2/api-docs/**","anon");
        stringStringHashMap.put("/webjars/springfox-swagger-ui/**","anon");
//        stringStringHashMap.put("/**","anon");

        stringStringHashMap.put("/**","jwt");
//        stringStringHashMap.put("/**", "authc");    //authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问

        //访问401和404页面不通过我们的Filter
//        stringStringHashMap.put("/**","anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(stringStringHashMap);
        return shiroFilterFactoryBean;
    }


    @Bean
    protected SessionStorageEvaluator sessionStorageEvaluator(){
        DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }



    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(MyRealm myRealm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm);
        //将自定义的realm交给安全管理器统一调度管理
        defaultWebSecurityManager.setRealm(myRealm);
//        defaultWebSecurityManager.setCacheManager(cacheManager());
        return defaultWebSecurityManager;
    }

    /**
     * 下面的代码是添加注解支持
     *
     * @return 添加注解支持
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        //解决重复代理问题 github#994
        //添加前缀判断 不匹配 任何Advisor
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * Description : 管理Subject主题对象，生命周期的组件，用户只是打印下生产销毁日志什么，参考spring中bean的生命周期
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return  new LifecycleBeanPostProcessor();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

//    /**
//     * cacheManager 缓存 redis实现, 使用的是shiro-redis开源插件
//     *
//     * @return RedisCacheManager
//     */
//    @Bean
//    public RedisCacheManager cacheManager(){
//        RedisCacheManager redisCacheManager = new RedisCacheManager();
//        redisCacheManager.setRedisManager(redisManager());
//        redisCacheManager.setPrincipalIdFieldName("id");
//        redisCacheManager.setExpire(200000);
//        return redisCacheManager;
//    }



    /**
     * 配置shiro redisManager, 使用的是shiro-redis开源插件
     *
     * @return RedisManager
     */
    private RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setTimeout(0);
        return redisManager;
    }




    @Bean(name="redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);
        // value值的序列化采用fastJsonRedisSerializer
        template.setValueSerializer(serializer);
        template.setHashValueSerializer(serializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }


}
